const express = require('express');
const cors = require('cors');
const dotenv = require('dotenv');
const { createClient } = require('redis');
const jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const winston = require('winston');
const crypto = require('crypto');
const { sendVerificationEmail, verifyEmailConfig } = require('./email');
const config = require('./config');
const connectDB = require('../config/db');
const categoryRouter = require('../routes/category');

// 加载环境变量
dotenv.config();

// 配置日志记录器
const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    transports: [
        new winston.transports.File({ filename: 'error.log', level: 'error' }),
        new winston.transports.File({ filename: 'combined.log' })
    ]
});

if (process.env.NODE_ENV !== 'production') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

const app = express();

// 配置信任代理
app.set('trust proxy', 1);

// 创建Redis客户端
let redisClient;
if (config.useRedis) {
    redisClient = createClient({
        url: config.redisUrl
    });
} else {
    // 使用内存存储
    const memoryStore = new Map();
    redisClient = {
        connect: async () => {},
        set: async (key, value, options) => {
            memoryStore.set(key, value);
            if (options?.EX) {
                setTimeout(() => memoryStore.delete(key), options.EX * 1000);
            }
        },
        get: async (key) => memoryStore.get(key),
        del: async (key) => memoryStore.delete(key),
        incr: async (key) => {
            const value = parseInt(memoryStore.get(key) || '0') + 1;
            memoryStore.set(key, value.toString());
            return value;
        },
        expire: async (key, seconds) => {
            setTimeout(() => memoryStore.delete(key), seconds * 1000);
        }
    };
}

// 安全中间件
app.use(helmet({
    crossOriginResourcePolicy: { policy: "cross-origin" },
    crossOriginEmbedderPolicy: false
}));
app.use(cors({
    origin: '*',
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
    exposedHeaders: ['Content-Length', 'X-Foo', 'X-Bar'],
    credentials: true,
    maxAge: 86400 // 预检请求结果缓存24小时
}));
app.use(express.json());

// 注册路由
app.use('/api/category', categoryRouter);

// 添加根路由处理程序
app.get('/', (req, res) => {
    res.json({
        status: 'ok',
        message: '服务器运行正常',
        timestamp: new Date().toISOString()
    });
});

// 请求频率限制
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 100, // 限制每个IP 15分钟内最多100个请求
    message: '请求过于频繁，请稍后再试',
    standardHeaders: true,
    legacyHeaders: false,
    trustProxy: true
});
app.use(limiter);

// 验证码发送频率限制
const codeLimiter = rateLimit({
    windowMs: 60 * 1000, // 1分钟
    max: 1, // 限制每个IP 1分钟内最多发送1次验证码
    message: '发送验证码过于频繁，请稍后再试',
    standardHeaders: true,
    legacyHeaders: false,
    trustProxy: true
});

// 生成安全的验证码
function generateSecureVerificationCode() {
    return crypto.randomInt(100000, 1000000).toString().padStart(6, '0');
}

// 检查邮箱是否在黑名单中
async function isEmailBlacklisted(email) {
    const blacklistKey = `blacklist:${email}`;
    const blacklistStatus = await redisClient.get(blacklistKey);
    return blacklistStatus === 'true';
}

// 记录验证码尝试次数
async function incrementCodeAttempts(email) {
    const attemptsKey = `attempts:${email}`;
    const attempts = await redisClient.incr(attemptsKey);
    if (attempts === 1) {
        await redisClient.expire(attemptsKey, 300); // 5分钟过期
    }
    return attempts;
}

// 发送验证码接口
app.post('/api/sendCode', codeLimiter, async (req, res) => {
    try {
        const { email } = req.body;
        
        logger.info('发送验证码请求', { email, ip: req.ip });

        if (!/^[a-zA-Z0-9._%+-]+@qq\.com$/.test(email)) {
            logger.warn('无效的邮箱格式', { email });
            return res.status(400).json({
                success: false,
                message: '请输入有效的QQ邮箱'
            });
        }

        if (await isEmailBlacklisted(email)) {
            logger.warn('邮箱在黑名单中', { email });
            return res.status(403).json({
                success: false,
                message: '该邮箱已被限制使用'
            });
        }

        const code = generateSecureVerificationCode();
        
        await redisClient.set(`verify_code:${email}`, code, {
            EX: 300
        });

        try {
            await sendVerificationEmail(email, code);
            logger.info('验证码发送成功', { email });
            res.json({
                success: true,
                message: '验证码已发送到您的邮箱'
            });
        } catch (emailError) {
            logger.error('邮件发送失败', { error: emailError.message, email });
            await redisClient.del(`verify_code:${email}`);
            throw emailError;
        }
    } catch (error) {
        logger.error('发送验证码失败', { error: error.message, email: req.body.email });
        res.status(500).json({
            success: false,
            message: '发送验证码失败'
        });
    }
});

// 邮箱登录接口
app.post('/api/emailLogin', async (req, res) => {
    try {
        const { email, code } = req.body;

        logger.info('登录请求', { email, ip: req.ip });

        if (!/^[a-zA-Z0-9._%+-]+@qq\.com$/.test(email)) {
            logger.warn('无效的邮箱格式', { email });
            return res.status(400).json({
                success: false,
                message: '请输入有效的QQ邮箱'
            });
        }

        if (await isEmailBlacklisted(email)) {
            logger.warn('邮箱在黑名单中', { email });
            return res.status(403).json({
                success: false,
                message: '该邮箱已被限制使用'
            });
        }

        if (!/^\d{6}$/.test(code)) {
            logger.warn('无效的验证码格式', { email });
            return res.status(400).json({
                success: false,
                message: '无效的验证码格式'
            });
        }

        const storedCode = await redisClient.get(`verify_code:${email}`);
        
        if (!storedCode || storedCode !== code) {
            const attempts = await incrementCodeAttempts(email);
            
            if (attempts >= 5) {
                await redisClient.set(`blacklist:${email}`, 'true', {
                    EX: 24 * 60 * 60 // 24小时
                });
                logger.warn('邮箱被加入黑名单', { email, attempts });
                return res.status(403).json({
                    success: false,
                    message: '验证码错误次数过多，账号已被临时限制'
                });
            }

            logger.warn('验证码错误', { email, attempts });
            return res.status(400).json({
                success: false,
                message: '验证码错误或已过期'
            });
        }

        const token = jwt.sign(
            { email },
            config.jwtSecret,
            { expiresIn: '7d' }
        );

        await redisClient.del(`verify_code:${email}`);
        await redisClient.del(`attempts:${email}`);

        logger.info('登录成功', { email });
        res.json({
            success: true,
            message: '登录成功',
            data: {
                token,
                email
            }
        });
    } catch (error) {
        logger.error('登录失败', { error: error.message, email: req.body.email });
        res.status(500).json({
            success: false,
            message: '登录失败'
        });
    }
});

// 启动服务器
async function startServer() {
    try {
        // 连接数据库
        await connectDB();
        console.log('=================================');
        console.log('MongoDB 连接成功');
        console.log('=================================');

        await redisClient.connect();
        console.log('=================================');
        console.log('Redis 连接成功');
        console.log('=================================');

        const isEmailConfigValid = await verifyEmailConfig();
        if (!isEmailConfigValid) {
            console.error('邮件服务配置无效，请检查邮箱设置');
            process.exit(1);
        }
        console.log('=================================');
        console.log('邮件服务配置验证成功');
        console.log('=================================');

        app.listen(config.port, '0.0.0.0', () => {
            console.log('=================================');
            console.log(`服务器运行在 http://0.0.0.0:${config.port}`);
            console.log('=================================');
        });
    } catch (error) {
        console.error('服务器启动失败:', error.message);
        process.exit(1);
    }
}

startServer(); 